import React, {FC, useCallback, useEffect, useMemo, useRef, useState} from "react";
import "./css/FormAdd.less";
import {useTranslation} from "react-i18next";
import useStateRef from "../../../customUse/useStateRef";
import {Button, Input, Select, Spin, Switch, Table} from "antd";
import {closeModal, updataModalFooter} from "../../../services/ModalService";
import {AxiosGet, AxiosSer} from "../../../services/HttpService";
import {getFormView} from "../../../services/ViewService";
import {coreDispatch} from "../../../utils/StoreUtil";
import useThrottle from "../../../customUse/useThrottle";
import FormLinkageControlModal from "./FormLinkageControlModal";
import GlobalIcon from "../../../global/GlobalIcon.tsx";
import BaseForm from "../../../module/form/BaseForm.tsx";
import CreateModal from "../CreateModal.tsx";
import {showMessage} from "../../../reducer/MsgReducer.tsx";

interface FormAddProps {
    modalKey: string,
    formType: string,
    type: string,
    view?: string,
    flowData: any[]
}

const FormAdd: FC<FormAddProps> = (props) => {
    const {t} = useTranslation();

    const formRef = useRef();
    const dataRef = useRef([]);
    const viewRef = useRef([]);
    const ruleRef = useRef([]);
    const linkageControlRef = useRef("");

    const [rule, setRule] = useStateRef([], ruleRef),
        [view, setView] = useStateRef([], viewRef),
        [columns, setColumns] = useState<any[]>([]),
        [dataSource, setDataSource] = useStateRef([], dataRef),
        [loading, setLoading] = useState<boolean>(false);

    const isCreate: Function = useCallback(() => {
        return props.type === "create";
    }, [props.type]);

    const isCopy: Function = useCallback(() => {
        return props.type === "copy";
    }, [props.type]);

    const handleChange: Function = (index: number, fields: string[], value: any) => {
        let row = [...dataRef.current];
        let node: any = row[index];
        fields.forEach(field => {
            node[field] = value[field];
        });
        setDataSource(row);
    };

    const handleChangeIndex: Function = (index: number, change: number) => {
        let targetI: number = index + change,
            row: any = [...dataRef.current],
            tempIRow: any = row[index];
        if (targetI > row.length - 1) {
            return;
        }
        row.splice(index, 1, row[targetI]);
        row.splice(targetI, 1, tempIRow);
        setDataSource(row);
    };

    const handleDelete: Function = (index: number) => {
        let row = [...dataRef.current];
        row.splice(index, 1);
        setDataSource(row);
    };

    const handleAdd: Function = useCallback(() => {
        let newNode = {
            id: Math.random(),
            optType: "add",
        };
        setDataSource([...dataSource, newNode])
    }, [dataSource]);

    const handleAddRule: Function = useCallback((index: number, field: string) => {
        coreDispatch("modalReducer/createModal", {
            key: "addRule",
            modalProps: {
                title: t("addRule"),
                width: 500,
            },
            component: CreateModal,
            comProps: {
                url: "/sf-drs/platform/view/saveViewRule",
                view: "form_rule_create"
            },
            onFinish: (result: any) => {
                if (result) {
                    setRule([{
                        id: result.data.id,
                        description: result.data.description,
                    }, ...ruleRef.current]);
                    handleChange(index, [field], {[field]: result.data.id});
                }
            }
        })
    }, [rule]);

    const handleEditRule: Function = useCallback((viewRuleId: string) => {
        let node: any = ruleRef.current.find(item => item.id === viewRuleId);
        coreDispatch("modalReducer/createModal", {
            key: "editRule",
            modalProps: {
                title: t("editRule"),
                width: 500,
            },
            component: CreateModal,
            comProps: {
                type: "edit",
                url: "/sf-drs/platform/view/saveViewRule",
                view: "form_rule_create",
                flowData: [node]
            },
            onFinish: () => {
            }
        })
    }, [rule]);

    const onOk: Function = useThrottle(async () => {
        if (!formRef.current) {
            return;
        }
        const {formType = "form"}: { formType: string } = props;
        let values = await formRef.current.validateFields();
        let requireAttrs: string[] = ["zhCn", "usEn", "ptBr", "field"];
        for (let item of dataRef.current) {
            for (let attrName of requireAttrs) {
                if (!item[attrName]) {
                    showMessage({
                        type: "error",
                        msg: t("notNullValue")
                    })
                    return;
                }
            }
        }
        let submitList: any[] = [], params: any = {
            type: formType,
            linkageControl: linkageControlRef.current,
            ...values
        };
        dataRef.current.forEach((item: any, index: number) => {
            submitList.push({
                id: item.optType === "add" ? undefined : item.id,
                zhCn: item.zhCn,
                usEn: item.usEn,
                ptBr: item.ptBr,
                field: item.field,
                isEditable: item.editable === undefined || item.editable ? 1 : 0,
                isNullable: item.nullable === undefined || item.nullable ? 1 : 0,
                isVisible: item.visible === undefined || item.visible ? 1 : 0,
                valueField: item.valueField,
                defaultValue: item.defaultValue,
                valueText: item.valueText,
                viewRuleId: item.viewRuleId,
                description: item.description,
                index: index + 1
            })
        });
        params["fields"] = submitList;
        setLoading(true);
        let result: any = await AxiosSer("/sf-drs/platform/view/saveFormView", "POST", params);
        setLoading(false)
        result.code == "1" && await closeModal(props.modalKey, async () => {
            return {data: params, ...result};
        })
    }, 2000, [dataSource, props.formType]);

    const createEditSelectRule: Function = useCallback((field: string) => {
        return (text: string, node: any, index: number) => {
            return <Select
                allowClear
                showSearch
                popupMatchSelectWidth={false}
                style={{width: "100%"}}
                fieldNames={{label: "description", value: "id"}}
                value={text}
                options={ruleRef.current}
                filterOption={(inputValue: string, option: any) => {
                    return option["description"] && option["description"].indexOf(inputValue) !== -1;
                }}
                onChange={value => {
                    handleChange(index, [field], {[field]: value})
                }}
                notFoundContent={
                    <Button style={{width: "100%"}} icon={<GlobalIcon style={{fontSize: 10}} name="icon-create"/>}
                            onClick={() => {
                                handleAddRule(index, field);
                            }}
                    >{t("add")}</Button>}
            />
        }
    }, [rule]);

    const createEditInput: Function = useCallback((field: string) => {
        return (text: string, node: any, index: number) => {
            return <Input style={{width: "100%"}} value={text} onChange={e => {
                handleChange(index, [field], {[field]: e.target.value})
            }}/>;
        }
    }, []);

    const createEditSwitch: Function = useCallback((field: string) => {
        return (text: boolean, node: any, index: number) => {
            return <Switch defaultChecked style={{width: "100%"}} checked={text} onChange={value => {
                handleChange(index, [field], {[field]: value})
            }}/>;
        }
    }, []);

    const createEditInputTextArea: Function = useCallback((field: string) => {
        return (text: string, node: any, index: number) => {
            return <Input.TextArea style={{width: "100%"}} value={text} rows={1} onChange={e => {
                handleChange(index, [field], {[field]: e.target.value})
            }}/>;
        }
    }, []);

    const createOpt: Function = useCallback(() => {
        return (text: string, node: any, i: number) => {
            return (<
                Button.Group>
                <Button
                    icon={
                        <GlobalIcon name="icon-put-away"/>
                    }
                    onClick={() => handleChangeIndex(i, -1)}
                />
                <Button icon={<GlobalIcon name="icon-launch"/>} onClick={() => handleChangeIndex(i, 1)}/>
                <Button
                    icon={
                        <GlobalIcon name="icon-delete"/>
                    }
                    onClick={() => handleDelete(i)}
                />
                {
                    node.viewRuleId ? (<Button icon={<GlobalIcon name="icon-edit"/>}
                                               onClick={() => handleEditRule(node.viewRuleId)}/>) : null
                }
            </Button.Group>)
        }
    }, []);

    const loadRules: Function = useCallback(async () => {
        const {data} = await AxiosGet("/sf-drs/platform/view/getAllViewRules");
        setRule(data)
    }, []);

    const loadView: Function = useCallback(async () => {
        const {view = "form_view_create", flowData = []}: { view: string, flowData: any[] } = props;
        let editData: any = {};
        if (props.type !== "create") {
            editData = {
                id: isCopy() ? undefined : flowData[0].id,
                name: flowData[0].name,
                config: flowData[0].config,
                description: flowData[0].description
            }
        }
        let result: any = await getFormView(view, editData);
        setView(result.form);
    }, [props.view, props.type, props.flowData]);

    const loadColumns: Function = useCallback(async () => {
        let columns: any[] = [];
        let {form = []}: { form: any } = await getFormView("form_view_form_create");
        // let form = [];
        columns = form.map((item: any) => {
            let renderCom: Function = createEditInput(item.field),
                width = 150;
            if (["editable", "nullable", "visible"].indexOf(item.field) !== -1) {
                width = 50;
                renderCom = createEditSwitch(item.field);
            } else if (item.field === "viewRuleId") {
                width = 200;
                renderCom = createEditSelectRule(item.field);
            } else if (item.field === "description") {
                renderCom = createEditInputTextArea(item.field);
            } else if (item.field === "defaultValue") {
                renderCom = createEditInputTextArea(item.field);
            }
            return {
                title: <>{item.title} {item.required ? <span style={{color: "red"}}>*</span> : null}</>,
                dataIndex: item.field,
                align: "center",
                width: width,
                render: renderCom
            }
        });
        columns.push({
            title: t("opt"),
            dataIndex: "opt",
            width: 120,
            render: createOpt()
        });
        setColumns(columns);
    }, [rule]);

    const loadData: Function = useCallback(async () => {
        let row: any[] = [];
        if (isCreate()) {
            row = [];
        } else {
            const {flowData = []}: { flowData: any[] } = props;

            let {data}: {
                data: any
            } = await AxiosGet("/sf-drs/platform/view/getFormViewDetails", {viewName: flowData[0].name});
            if (data.linkageControl) {
                linkageControlRef.current = data.linkageControl;
            }
            row = data.fields.map((item: any) => {
                return {
                    id: isCopy() ? undefined : item.id,
                    zhCn: item.zhCn,
                    usEn: item.usEn,
                    ptBr: item.ptBr,
                    field: item.field,
                    editable: !!item.isEditable,
                    nullable: !!item.isNullable,
                    visible: !!item.isVisible,
                    defaultValue: item.defaultValue,
                    valueField: item.valueField,
                    valueText: item.valueText,
                    viewRuleId: item.viewRuleId,
                    description: item.description,
                }
            });
        }

        setDataSource(row);
    }, [props]);

    const init: Function = useCallback(async () => {
        await Promise.all([loadRules(), loadView()]);
        loadColumns();
        loadData();
    }, []);

    const handleLinkageControl: Function = useCallback((index: number, field: string) => {
        coreDispatch("modalReducer/createModal", {
            key: "linkageControl",
            modalProps: {
                title: t("linkageControl"),
                width: 1200,
            },
            component: FormLinkageControlModal,
            comProps: {
                value: linkageControlRef.current
            },
            onFinish: (result: any) => {
                if (result) {
                    linkageControlRef.current = result;
                }
            }
        })
    }, [rule]);


    useEffect(() => {
        init();
    }, []);

    useEffect(() => {
        updataModalFooter(props.modalKey, [
            <Button key="linkageControl"
                    onClick={handleLinkageControl}>{t("linkageControl")}</Button>,
            <Button key="cancel"
                    onClick={() => {
                        closeModal(props.modalKey, false)
                    }}>{t("cancel")}</Button>,
            <Button key="finish" type="primary"
                    onClick={onOk}>{t("determine")}</Button>])
    }, []);

    const renderForm = useMemo(() => {
        return (
            <div className="sf_core_view_form_add_form">
                <BaseForm
                    init={formRef}
                    formItemLayout={2}
                    view={view}
                />
            </div>
        )
    }, [view, props]);

    const renderTable = useMemo(() => {
        return (
            <div className="sf_core_view_form_add_table">
                <Table
                    columns={columns}
                    dataSource={dataRef.current}
                    pagination={false}
                    size={'small'}
                    bordered={true}
                    rowKey={'id'}
                    footer={() => {
                        return (
                            <div className="sf_core_view_form_add_table_footer">
                                <Button onClick={handleAdd} icon={<GlobalIcon style={{fontSize: 10}}
                                                                              name="icon-create"/>}>{t("add")}</Button>
                            </div>
                        )
                    }}
                />
            </div>
        )
    }, [columns, dataSource, rule, props]);

    const renderFormAdd = useMemo(() => {
        return (
            <Spin spinning={loading} wrapperClassName="sf_core_view_form_add">
                {renderForm}
                {renderTable}
            </Spin>
        )
    }, [view, loading, columns, dataSource, props]);

    return (renderFormAdd);
};

export default FormAdd;